// Author: wsfuyibing <682805@qq.com>
// Date: 2025-05-15

package arcade

import (
	"context"
	"gitee.com/go-libs/db-xorm/db"
	"gitee.com/go-libs/runtime"
	"github.com/kataras/iris/v12"
	"net/http"
	"regexp"
	"server/app/config"
	"server/app/errs"
	"server/app/http/models"
	"server/app/http/services"
	"server/app/kind"
	"strconv"
)

var (
	regexMatchHeaderValue = regexp.MustCompile(`\s+(\d+)$`)
	unknownAdmin          = &models.ArcadeAdmins{}
)

const (
	arcadeKey      = "__ContextArcade__"
	arcadeAdminKey = "__ContextArcadeAdmin__"
)

type (
	// Master
	// 钓场管理员.
	Master interface {
		GetAdmin(i iris.Context) *models.ArcadeAdmins
		GetArcade(i iris.Context) (arcade *models.Arcades, admin *models.ArcadeAdmins)
		GetArcadeId(i iris.Context) (int64, error)

		// InitCalendar
		// 初始化钓场日历.
		//
		// 读取当天数据, 若不存在则创建.
		InitCalendar(ctx context.Context, aid kind.ArcadeId) (calendar *models.ArcadeCalendar, err error)
		Set(i iris.Context, arcade *models.Arcades, admin *models.ArcadeAdmins)
		Unset(i iris.Context)
		Verify(ctx context.Context, uid kind.UserId, aid int64) (arcade *models.Arcades, admin *models.ArcadeAdmins, err error)
	}

	master struct {
	}
)

func (o *master) GetAdmin(i iris.Context) (arcade *models.ArcadeAdmins) {
	return i.Values().Get(arcadeAdminKey).(*models.ArcadeAdmins)
}

func (o *master) GetArcade(i iris.Context) (arcade *models.Arcades, admin *models.ArcadeAdmins) {
	return i.Values().Get(arcadeKey).(*models.Arcades), o.GetAdmin(i)
}

// GetArcadeId
// 取钓场ID.
//
// 从HTTP请求头中获取对象钓场ID.
func (o *master) GetArcadeId(i iris.Context) (int64, error) {
	var str string

	if str = i.Request().Header.Get(config.Arcade.GetHeaderName()); str == "" {
		return 0, errs.ErrMasterArcadeIdNotSpecified
	}

	if m := regexMatchHeaderValue.FindStringSubmatch(str); len(m) == 2 {
		if n, err := strconv.ParseInt(m[1], 10, 64); err == nil && n > 0 {
			return n, nil
		}
	}

	return 0, errs.ErrMasterArcadeIdNotValid
}

// InitCalendar
// 日历初始化.
func (o *master) InitCalendar(ctx context.Context, aid kind.ArcadeId) (calendar *models.ArcadeCalendar, err error) {
	var (
		dt   = db.NewDate()
		has  bool
		sess *db.Session
	)

	if sess, err = db.Config.GetMaster(ctx); err != nil {
		err = errs.ErrDatabaseQuery
		return
	}

	calendar = &models.ArcadeCalendar{}

	if has, err = sess.Table(models.ArcadeCalendar{}).Where("`arcade_id` = ? AND `date` = ?", aid, dt).Get(calendar); err != nil {
		err = errs.ErrDatabaseQuery
	} else if !has {
		calendar.ArcadeId = aid
		calendar.Date = dt
		if _, err = sess.Insert(calendar); err != nil {
			err = errs.ErrDatabaseQuery
		}
	}
	return
}

func (o *master) Set(i iris.Context, arcade *models.Arcades, admin *models.ArcadeAdmins) {
	i.Values().Set(arcadeKey, arcade)
	i.Values().Set(arcadeAdminKey, admin)
}

func (o *master) Unset(i iris.Context) {
	i.Values().Remove(arcadeKey)
	i.Values().Remove(arcadeAdminKey)
}

func (o *master) Verify(ctx context.Context, uid kind.UserId, aid int64) (arcade *models.Arcades, admin *models.ArcadeAdmins, err error) {
	var has bool

	// 1. 校验钓场.
	if arcade, has, err = services.NewArcadesService().Dao.GetById(ctx, aid); err != nil {
		err = errs.ErrDatabaseQuery
		return
	} else if !has {
		err = errs.ErrArcadeNotFound
		return
	}

	// 2. 钓场状态.
	if !arcade.State.IsEnabled() {
		err = runtime.NewError(http.StatusBadRequest, arcade.State.Text())
		return
	}

	// 3. 校验管理员.
	if admin, has, err = services.NewArcadeAdminsService().Dao.GetByMap(ctx, map[string]any{
		"arcade_id": aid,
		"user_id":   uid,
	}); err != nil {
		err = errs.ErrDatabaseQuery
		return
	} else if !has || !admin.State.IsEnabled() {
		err = errs.ErrMasterArcadeAccessDenied
		return
	}

	// 4. 校验权限.
	return
}

func (o *master) init() *master {
	return o
}
